package org.infodavid.common.pool.impl;

import java.io.IOException;
import java.lang.ref.WeakReference;
import java.net.URL;
import java.util.Properties;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.pool.PoolableObjectFactory;
import org.apache.commons.pool.impl.GenericObjectPool;
import org.apache.commons.pool.impl.GenericObjectPool.Config;

import org.infodavid.common.text.TextUtil;

/**
 * The Class ConfigLoaderHelper.
 */
public final class ConfigLoaderHelper {

	/** The Constant LOG. */
	private static final Log LOG = LogFactory.getLog(ConfigLoaderHelper.class);

	/** The singleton. */
	private static WeakReference<ConfigLoaderHelper> singleton = null;

	/**
	 * returns the singleton.
	 * @return <code>ConfigLoaderHelper</code>
	 */
	public static synchronized ConfigLoaderHelper getInstance() {
		if (singleton == null || singleton.get() == null) {
			singleton = new WeakReference<ConfigLoaderHelper>(new ConfigLoaderHelper());
		}

		return singleton.get();
	}

	/**
	 * The Constructor.
	 */
	private ConfigLoaderHelper() {
		super();
	}

	/**
	 * Load.
	 * @param config the configuration object
	 * @param factory the source factory
	 * @param properties the properties
	 */
	@SuppressWarnings("static-access")
	public void load(final Config config, final Properties properties,
	    final PoolableObjectFactory factory) {
		final URL url =
		    getClass().getClassLoader().getSystemResource(
		        factory.getClass().getSimpleName() + ".properties");

		if (url == null) {
			if (LOG.isDebugEnabled()) {
				LOG.debug("No configuration found for pool: " + factory.getClass().getSimpleName());
			}

			config.maxIdle = GenericObjectPool.DEFAULT_MAX_IDLE;
			config.minIdle = GenericObjectPool.DEFAULT_MIN_IDLE;
			config.maxWait = GenericObjectPool.DEFAULT_MAX_WAIT;
			config.maxActive = GenericObjectPool.DEFAULT_MAX_ACTIVE;
			config.timeBetweenEvictionRunsMillis =
			    GenericObjectPool.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS;
			config.minEvictableIdleTimeMillis = GenericObjectPool.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
			config.testOnBorrow = GenericObjectPool.DEFAULT_TEST_ON_BORROW;
			config.testOnReturn = true;
			config.testWhileIdle = GenericObjectPool.DEFAULT_TEST_WHILE_IDLE;
			config.whenExhaustedAction = GenericObjectPool.WHEN_EXHAUSTED_GROW;
		}
		else {
			if (LOG.isDebugEnabled()) {
				LOG.debug("Loading configuration for pool: " + factory.getClass().getSimpleName());
			}

			try {
				properties.load(url.openStream());
				config.maxIdle =
				    TextUtil.toInt(properties.getProperty("maxIdle"), GenericObjectPool.DEFAULT_MAX_IDLE);
				config.minIdle =
				    TextUtil.toInt(properties.getProperty("minIdle"), GenericObjectPool.DEFAULT_MIN_IDLE);
				config.maxWait =
				    TextUtil.toLong(properties.getProperty("maxWait"), GenericObjectPool.DEFAULT_MAX_WAIT);
				config.maxActive =
				    TextUtil.toInt(properties.getProperty("maxActive"),
				        GenericObjectPool.DEFAULT_MAX_ACTIVE);
				config.timeBetweenEvictionRunsMillis =
				    TextUtil.toLong(properties.getProperty("timeBetweenEvictionRunsMillis"),
				        GenericObjectPool.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS);
				config.minEvictableIdleTimeMillis =
				    TextUtil.toLong(properties.getProperty("minEvictableIdleTimeMillis"),
				        GenericObjectPool.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS);
				config.testOnBorrow =
				    TextUtil.toBoolean(properties.getProperty("testOnBorrow"),
				        GenericObjectPool.DEFAULT_TEST_ON_BORROW);
				config.testOnReturn =
				    TextUtil.toBoolean(properties.getProperty("testOnReturn"),
				        GenericObjectPool.DEFAULT_TEST_ON_RETURN);
				config.testWhileIdle =
				    TextUtil.toBoolean(properties.getProperty("testWhileIdle"),
				        GenericObjectPool.DEFAULT_TEST_WHILE_IDLE);
				config.whenExhaustedAction = GenericObjectPool.WHEN_EXHAUSTED_GROW;
			}
			catch (final IOException e) {
				LOG.warn("An error occurs while loading configuration, using default configuration");
			}
		}
	}

	/**
	 * Instantiate.
	 * @param factory the factory
	 * @param properties the properties
	 * @param config the configuration object
	 * @return the object pool
	 */
	public GenericObjectPool instantiate(final PoolableObjectFactory factory,
	    final Properties properties, final Config config) {
		return new GenericObjectPool(factory, config);
	}
}
